Skip to content

feat(container-runner): exit process when the last child stops - #5587

Open
abcxff wants to merge 1 commit into
stack/feat-container-runner-drain-child-before-sigterm-on-engine-pause-yloxstwofrom
stack/feat-container-runner-exit-process-when-the-last-child-stops-ssuvmoso
Open

feat(container-runner): exit process when the last child stops#5587
abcxff wants to merge 1 commit into
stack/feat-container-runner-drain-child-before-sigterm-on-engine-pause-yloxstwofrom
stack/feat-container-runner-exit-process-when-the-last-child-stops-ssuvmoso

Conversation

@abcxff

@abcxff abcxff commented Aug 21, 2026

Copy link
Copy Markdown
Contributor

No description provided.

@claude

claude Bot commented Aug 21, 2026

Copy link
Copy Markdown
Contributor

Review: feat(container-runner): exit process when the last child stops

Small, focused change (24/-19 across actor.rs + main.rs) with a clear rationale: reap the instance immediately instead of waiting on the platform's own shutdown signal. Comments are updated in step with the behavior, which is good.

Potential bug: race between a stopping actor and a concurrently-starting actor on the same multi-actor instance

stop_child (container-runner/src/actor.rs:38) treats children().is_empty() as "this instance is now idle, exit," but the registry only gains an entry for a new actor after its child has finished spawning (on_start in actor.rs, insert happens post-spawn — see the comment near the children().insert_async call explaining registration is deliberately deferred until startup succeeds).

That creates a window: if actor A is the last actor on an instance and is being destroyed/slept while actor B is concurrently being placed (started) on the same instance, children() can appear empty to A's stop_child (because B has not inserted yet) even though B's child process is mid-spawn. A would then call request_exit, cancelling EXIT and driving main down the "actor-driven exit" path, which stops only children that are already registered and then shuts the runtime down and returns, ending the whole PID-1 process. B's not-yet-registered child would be orphaned (or torn down along with the process) even though B's on_start may go on to report success.

This directly undermines the stated purpose of the guard ("a multi-actor instance does not tear down siblings still hosting a child", actor.rs:52-55), since the check only sees registered siblings, not ones that are still starting. It is most exploitable on non-default pool concurrency > 1 setups (the doc comment in main.rs notes concurrency 1 is "the recommended game-server setup," so default deployments dodge this, but the code explicitly supports and guards for the concurrent case).

Worth considering: reserve a registry slot (or bump a "starting" counter) for a new actor before spawning its child, so the idle check in stop_child accounts for in-flight starts, not just running ones.

Test coverage

No test exercises the new exit-on-empty-registry path or the multi-actor guard (container-runner/tests/inline/ only has boot_id.rs and input.rs). Given this changes real production shutdown behavior, and the race above is timing-dependent, even a targeted unit/integration test around stop_child's empty-vs-non-empty branching would help pin down the intended semantics and guard against regressions.

Minor

  • The two log sites for the branch (request_exit's "shutting down container" vs. the else's "actor stopped, other actors still running on this instance") are easy to miss diffing side by side, but coverage/parity looks fine as written.

Overall the happy-path logic (single actor per instance, the recommended setup) looks correct, and the comment updates in main.rs accurately describe the new two-shape wait. The main thing I would want resolved before merge is the concurrent start/stop race for multi-actor instances, since the change's own guard is written specifically to protect that case.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant